#sentence and paragraph
TextFile='text'
NumP=1 #第几段
NumS=1 #一段的第几句话
get_P(){
	PLine=$(sed -En "$NumP {s/([。！；])/\1@AWK@/g;p}" $TextFile)
	#              {限定范围在这一段 \1保留标点符号  @AWK@ 用来分隔
}
get_P
get_S(){
	SLine=$(echo $PLine | awk -F'@AWK@' "{print \$$NumS}")
}
getS(){
	[[ $1 = 'pre' && $NumS -gt 1 ]] && let NumS--
	get_S && let NumS++
	if [[ $NumP -gt $(sed -n '$=' $TextFile) ]];then
		echo "最后一行啦"
		exit
	fi
	if [[ -z $SLine ]];then
		NumS=1
		let NumP++ && get_P
		get_S && let NumS++
		#echo 
	fi
	SLine="${SLine// /}" #消除空格， 空格对数组的拆分有影响
	#echo $s
	local t=$(($1-1))
	[[ $t =~ [1-9]+ ]] &&
	for i in $(seq $t);do getS;done
}
# TextFile 存放句子的文件
# NumS 第己句话
# NumP 第几段
# getS 函数，获取下一句话保存在SLine 中
 
pass(){
	return
}
CPR(){
	_PR1=
	_PR2=
	_PR3=
	_PR0=
}
Clear(){
	L=
	Index=0
}
quiet(){
	[[ -z $1 ]] && _Say_All='不鞥匹配' ||
	_Say_All=$(sed "s/^$1[^ ]* //" <<< $_Say_All)
}
say(){
	[[ $1 = add && $# -eq 2 ]] && {
		_Say_All_="$_Say_All_ $2";
		_Say_All="$_Say_All $2";
		echo "func: -->[$_Say_All_]";
		return 0;
	}
	[[ -z $1 ]] && _Say_All=$_Say_All_ ||
	_Say_All="$_Say_All $(grep  -Eo "$1\w*" <<< $_Say_All_)"
}
_bl=''
_bl_='    ·'
#_bl="$_bl$_bl_"  更美观的展示 函数栈调用 -->开始
#_bl=${_bl%$_bl_}	<--  结束 
# 写入Say函数,  通过传参数控制
Say(){
	(($#<2)) && { echo "警告，请输入两个变量"; }
	[[ $_Say_All =~ $1 ]] && {
		[[ $2 = start ]] && echo "$_bl···· > $1() {" && _bl="$_bl$_bl_" &&return
		[[ $2 = end ]] && _bl="${_bl%$_bl_}" && echo "$_bl} end $1"   &&return
		echo "$_bl$2" 
	}
	return 0 
}

_S= #双向栈 储存基本结构
__S= #返回删除的值
EN(){
	Say EN start
	(($#==3)) && local S=$3
	[[ $1 =~ in ]] && S=${S// /} &&
	[[ -z $S ]]  && Say EN "!!不要让S为空,退出不好排查错误" && Say EN end && return 1
#	[[ -z $S ]]  && return 1 #特别注意，上面这样写 Say的返回值必须为0 ！！！
	declare -n _S=$2
	if [[ $1 =~ out && -z $_S ]];then 
		Say EN "!!空队列 $2: []-->$1->[$S]"
		Say EN end
		return 1
	fi
	case $1 in
		rin|lin)
		Say EN "$2: [$_S]-->$1->[$S]" ;;
		rout)
		Say EN "$2: [$_S]-->$1->[${_S##* }]" ;;
		lout)
		Say EN "$2: [$_S]-->$1->[${_S%% *}]" ;;
	esac
	case $1 in
		lout|rout)
			if [[ $_S =~ ' ' ]];then
				[[ $1 = lout ]] && 
				__S=${_S%% } && _S=${_S#* }
				[[ $1 = rout ]] &&
				__S=${_S##* } && _S=${_S% *}
			else
				__S=$_S; _S=
			fi ;;
		lin|rin)
			((${#_S}==0)) && _S=$S || {
				[[ $1 = lin ]] && _S="$S $_S"
				[[ $1 = rin ]] && _S="$_S $S"
			} ;;
	esac
	Say EN end
	return 0
}
GXfile='z知识库'
Index=0
_sz='一二三四五六七八九十'
re_sz="[$sz十][零$sz十百千万亿兆]*"
re_xu='才还和与、, 或且在又的得地了'
re_dw='个次本瓶杯台双支张把回秒'
re_lc='因为|所以|只有|不仅|而且|但是'
re_dc='我们|这些|那些|他们|[我你它他她这那]'
re_fw='左右|上下|前后|大约|大概|可能|一定'
re_split="$re_fw|$re_dc|$re_lc|[$re_xu是$re_dw]|$re_sz"
split(){
	[[ $# -eq 0 ]] &&
	sed -E "s/$re_split/ & /g" $GXfile ||
	sed -E "s/$re_split/ & /g"
}
get单词__(){
	Say get单词__ start
	local len=1
	local re=1
	while ((len+Index<=${#SLine})) ;do
		S=${SLine:$Index:$len}
		if [[ $(grep -Eo "$S" $GXfile) =~ $S ]];then
			let len++
			re=0
		else
			break
		fi
	done
	let len--
	let Index+=$len
	S=${S:0:$len}
	Say get单词__ "[$re $S $Index:$len]" 
	Say get单词__ end
	return $re
}
#_Say_All=get单词__
#getS
#echo $SLine
#get单词__
#get单词__
#exit
get输入(){
	Say get输入 start
	Say get输入 "input:[$SLine]"
	Index=0
	local new=1
	local l=${#SLine}
	while ((Index<l)); do
		local _len=0
		while ! get单词__ ;do
			((new==1)) && _Index=$Index && new=0
			let Index++
			let _len++
			#echo $_Index:$_len t="${SLine:$_Index:$_len}"
			((Index==l)) && break
		done
		if ((new==0)) ;then
			new=1
			__t=$S
			S="${SLine:$_Index:$_len}"
			EN rin $1
			echo "<$S> 未识别,能说说是什么吗？:"
			S=$__t
		fi
		Say get输入 "[$S]"
		EN rin $1
	done
	Say get输入 end
}
#declare -n l=$a
#echo "${!a}"
#echo $l

get知识(){
	sed 's/。./。\n/g' <<<$line >> $GXfile
}

handle数字(){
	for t in $_S;do
		if [[ $SZ =~ $t ]];then
			_S=$(sed  "s/$t /$t/" <<< $_S)
			_T=$(sed  "s/数字 /数字/" <<< $_T)
		fi
	done
	echo $_S
}
解析(){
	local jx=$(echo $_PR0|awk '{
	for(i=NF;i>0;i--){
		if(i>NF-2)
			printf $i" "
		else
			printf $i
		}}'|sed 's/[)(]//g;')
	[[ $1 = 主干 ]] && 
	echo $jx|sed 's/([^[]*)//g;s/\[//g;s/\]//g;' || 
	echo $jx
}
re_xu='^(的|得|地|之|与|和|从|把|上|又|且|、)'
re_lian='[和与、]'
_sp_s='·' #one for awk -F  split
_sp_b='-' #one for awk -F  blank
_sb='[x-]'
_eq='等价于|=='

	#echo $times_str #!!!!什么鬼bug,哈哈。注释这条就可以正常运行。实在想不通是为什么
_str(){
	local file=$4
	case $1 in 
		isword)awk "{if(\$$3 ~ /^$2$|(^$2|$_sb$2)$_sb/)print $4}";;
		word)awk "{if(\$$3 ~ /\<$2\>/)print $4}"|sed "s/$_sb/ /g";;
		split)sed -nE "/$2/{s/ /$_sp_s/;s/(.)[是]/\1$_sp_s/;s/[。]/$_sp_s/g;s/[和与、 ]/$_sp_b/g;p}" $file|awk -F$_sp_s "{print $3}";;
		choose)awk "{for(i=1;i<=NF;i++)if(\$i ~ /$2/)print \$i}";;
		replace)sed -E "s/$2/$3/$4" ;;
	esac
}
str(){
	case $1 in 
		格式化)sed -n '/^$/!s/[^。]$/&。/g;p'  -i $GXfile;; #格式刷
		查找)_str split $2 '$0' $GXfile|sed -n "/\<$2\>/p";;
		联想)_str split $2 '$1,$3' $GXfile|_str word $2 0 $3;;
		扩展)_str split $2 '$1,$2' $GXfile|_str word $2 1 $3;;
		描述)_str split $2 '$1,$3' $GXfile|_str word $2 1 $3;;
		等价)_str split $2 '$1,$3' $GXfile|_str word $2 1 '$2'|_str choose $_eq|_str replace $_eq '' g;;
		匹配)grep "\<$2\>" ;;
	esac
}
#printf '\n: 查找 '
#str 查找 $w
#printf '\n: 联想'
#str 联想 $w '$0'
#printf '\n: 扩展 '
#str 扩展 $w '$2'
#printf '\n: 描述'
#str 描述 $w '$2'
search_扩展(){
	local re=1
	local re_t=
	declare -n local TT=$3
	for t in $TT;do
		re_t="<$1-$t>|<$t-$2>" 
		#特别注意，正则要写在变量里面
		[[ $# -eq 4 && $_search_ =~ $re_t ]] && continue
		#Say search "参数[$4][$_search_][$t]->[$1,$2]"
		#read __a #???读取其他函数的咯擦亮变量？bug？？？
		if [[ $4 = 右 ]];then
			search $1 $t '右扩展 搜索' && re=0 &&break
		else
			search $t $2 '左扩展 搜索' && re=0 &&break
		fi
	done
	return $re
}
_search_times=0
search(){
	# a + ... 1. search?   2. extent a?  3. extent ...
	Say search start
	[[ -z $2 || -z $1 ]] && 
	Say search "输入为空<$1><$2>" && 
	Say search end &&return 1

	local re=0
	[[ $1$2 =~ \<无中心词\>|\<无匹配\> ]] && Say search end && return 1

	local _text=$(str 描述 $1 '$2'|str 匹配 $2)
	Say search "--->搜索  [$1 $2] $3"
	let _search_times++
	read ___a
	if [[ -z $_text ]];then 
	for _a_ in 1;do
		#标记这是根搜索，如果待会扩展有$1-$2,就跳过
		_search_="${_search_} <$1-$2>"
		Say search "<$1><$2> [$3]匹配: [$_text]"
		Say search "[$_search_times]搜索链 $_search_"

		local _ex_=$(str 扩展 $1 '$2')
		Say search "->左扩展  [$1]是<${_ex_}>"
		search_扩展 $1 $2 _ex_ 左
		re=$? && ((re==0)) && break

		_ex_=$(str 等价 $1)
		Say search "->左等价  [$1]是<$_ex_>"
		search_扩展 $1 $2 _ex_ 左
		re=$? && ((re==0)) && break
		#左边扩展

		_ex_=$(str 扩展 $2 '$2')
		Say search "->右扩展  [$2]是<${_ex_}>"
		search_扩展 $1 $2 _ex_ 右
		re=$? && ((re==0)) && break
		#右边扩展
		_ex_=$(str 等价 $2)
		Say search "->右等价  [$2]是<$_ex_>"
		search_扩展 $1 $2 _ex_ 右
		re=$? && ((re==0)) && break
	done
	fi
	Say search "<---[$re]结束[$1]<---[$_text]"
	(($#==2)) && _search_= #标记结束 标记这是根搜索，如果待会扩展有$1,就跳过
	Say search end
	return $re
}
	
re_fh="[。！；“\"!’\'”‘《》<>.]"
re_fx="[上下左右中]"
_set_中心词(){
	Say _set_中心词 start
	Say _set_中心词 "设置中心词<$a><$b>"
	local a=$1
	local b=$2
	#local a,b search_扩展 函数read a改变了，！！！
	local re=0
	declare -n sss=$3
	declare -n line_t=$4
	local zx=
	if [[ $a = 的 ]] || search $b $a;then
		zx=2
	elif search $a $b;then
		zx=1
	else 
		zx=0
	fi
	case $zx in 
		0)
			Say check "[ss:$p 无中心词]"; 
			p="[$a;$b]"; re=1 ;;
		1)
			p="[$a]($b)";
			Say _set_中心词 "[ss:$p]"; sss=$a ;;
		2)
			p="($a)[$b]"
			Say _set_中心词 "[ss:$p]"; sss=$b ;;
	esac
	Say _set_中心词 "[$re] $4:[$p]--->[$line_t]"
	EN lin $4 "$p"
	Say _set_中心词 end
	return $re
}
check分析(){
	Say check start
	local re=0; local i=0
	local a=; local b=;
	local p=; local first=yes
	declare -n line=$1
	declare -n line_t=$2
	Say check "input:[$line]"
	[[ $# -eq 3 ]] && declare -n ss=$3 || local ss=
	while true;do
		read ____a
		a=; b=; p=
		EN rout $1 && local b=$__S 
		EN rout $1 && local a=$__S || local end=yes
		Say check "> $i $1:[$line],  $2:[$line_t], in:[$a $b][$ss]"
		S=$a$b
		[[ $end != yes && -z $ss ]] && _set_中心词 $a $b ss $2 && {
			let i++
			Say check "> $i $1:[$line]<--[$S], $2:[$line_t], in:[$a $b][$ss]"
			EN rin $1;first=no
			let i++
			continue
		} #为了较少不必要的search

		if [[ $end = yes || -z $ss ]];then
			p=$S
			pass
		elif [[ $a =~ $re_fh ]];then
			p=$S
			Say check "[[$a, $b] 标点符号]"
		elif search $a $ss;then
			p="[$a]($b)"
			Say check "[$a] <--- $p[ss]"; ss=$a
		elif search $ss $a;then
			p="($a)[$b]"
			Say check "[($a)--->[$ss]($b)]"
		else
			# 检查是否为空，否则死循环
			[[ -z $line ]] && {
				Say check "--->[结束: [[$a] ! [$ss]($b)]"
				Say check "> $i $1:[$line]<--[$S], $2:[$p]-->[$line_t], in:[$a $b][$ss]"
				[[ ! -z $S ]] && EN rin $1
				[[ ! -z $a ]] && a="$a;"
				p=$a$b && EN lin $2 $p
				Say check "->end:[$re][$ss] $1:|$line| $2:|$line_t|"
				_ss=$ss
				Say check end
				return 1
			}
			Say check "-->[进入分句: [[$a] ! [$ss]($b)]"
			EN rin $1 $a
			# 返回 处理结果 __S, 这里注意：分句的结果保存在T($2)！！！
			# 注意，ss是局部变量，注意传参数__ss, 而且要为空
			local __ss=
			check分析 $1 $2 __ss && [[ ! -z $__ss ]] && re=0 || {
				Say check "->[1][分句返回:($line)[$__ss] ! [$ss]($b) 否]"
				end=yes; 
				p="$line。$b" && EN lin $2 $p
				Say check "-->[分句返回失败。]"
				S="$line$b" && EN rout $1;
			}
			# 跳循环之前要记得设置状态！ re=0 为true
			[[ $end = yes ]] || if search $__ss $ss ;then 
				Say check "->[0][分句返回:($line)[$__ss]<---[$ss]($b) ok] [ch]"
				p="[$line]($b)" 
				S=$line$b && EN rout $1
			elif search  $ss $_ss ;then
				Say check "->[0][分句返回:($line)[$__ss]--->[$ss]($b) ok]"
				p="($line)[$b]"
				S=$line$b && EN rout $1
			else 
				Say check "->[1][分句返回:($line)[$_ss] ! [$ss]($b) 否]"
				re=1; end=yes;
				EN rout $1 && S="$line$b";
				p="$line。$b" && EN lin $2 $p
				Say check "-->[分句匹配失败。]"
			fi
		fi 
		[[ $end = yes ]] && {
			[[ ! -z $S ]] && EN rin $1
			Say check "->end:[$re][$ss] $1:|$line| $2:|$line_t|"
			_ss=$ss
			Say check end
			return $re
		}
		Say check "> $i $1:[$line]<--[$S], $2:[$p]-->[$line_t], in:[$a $b][$ss]"
		EN lin $2 $p #re=0必定执行，除了break(re=1)
		EN rin $1
		let i++
	done
	Say check分析 end
}
_Say_All_='check分析 _set_中心词 EN search get输入 get单词__' 
_Say_All=$_Say_All_
main(){
	str 格式化 #为每一行的末尾增加一个句号
	quiet
	say check分析
	say _set_中心词
	for j in {1.1};do
		getS 1
		SLine='我是一个AI的开创性人物'
		SLine='有性别'
		SLine='李英海有'
		SLine='你是AI'
		SLine='你有性别'
		SLine='李英海有智慧'
		SLine='你是智慧的AI'
		SLine='你有无穷的智慧'

		say search
		#SLine=$(split)
		SLine=$(echo $SLine | split a)
		echo [$SLine]
		LL=;T= #LL 输入，T输入
		get输入 LL
		check分析 LL T
		echo "[$?]main  LL:[$LL], T:[$T]"
		echo "_str:[$times_str],_search:[$_search_times]"
	done
}
main

